﻿using LowCoding.Common.Security;
using LowCoding.Common;
using LowCoding.Domain.Entity;
using LowCoding.Dto;
using LowCoding.Dto.Sys;

namespace LowCoding.Application.Sys.Right
{
    public class SysRightService : ServiceBase<SysModule, SysModuleInput, SysModuleOutput, SysModuleSearchInput, string>, ISysRightService
    {
        /// <summary>
        /// 根据用户id查询用户权限***
        /// </summary>
        /// <returns></returns>
        public async Task<List<TreeMainDto>> GetRoleRightsMod(string userId)
        {
            //逐层获取ID最终获取到模块表信息 存储起来 t是用户角色表 t1是角色权限表 t2是模块表
            //三表联查用户角色表、角色表、模块表 使用的内连接
            //Inner.Join 是SqlSugar 中的链接方法操作
            //用户角色表中的角色Id 链接角色表的Id
            //角色表的模块Id 链接模块表的Id 
            //根据条件用户角色表的Id 等于传过来参数的用户Id
            //把查询出来的数据 赋值给 new出来的AppModuleDto中
            var data = await _client.Queryable<SysUserrole>()
                      .InnerJoin<SysRight>((t, t1) =>t.RleId== t1.RgtRoleId)
                      .InnerJoin<SysModule>((t, t1, t2) => t1.RgtMdlId == t2.Id)
                      .Where((t, t1, t2) => t.UerId == userId)
                      .Distinct()
                      .Select((t, t1, t2) => new AppModuleDto
                      {
                           Id = t2.Id,
                           ModuleCode = t2.MdlCode,
                           ModuleName = t2.MdlName,
                           ParentModuleCode = t2.MdlParent,
                           IconCls = t2.MdlIconcls,
                           ModuleSeq = t2.MdlSeq,
                           path = t2.MdlUrl,
                           ModuleUrl = t2.MdlUrl,
                           ModuleType = t2.MdlType
                      }).ToListAsync();
            var mdlViews = new List<TreeMainDto>();

            //ParentModuleCode父模块功能 用上面三表联查查出来的数据加查询条件
            var firstModules = data.Where(c => c.ParentModuleCode == AppModuleDto.RootModuleCode).OrderBy(c => c.ModuleSeq).ToList();
            //把查询出来的根节点Code foreach循环赋值 添加到 实例化出来的 空TreeMainDto 
            foreach (var mdl in firstModules)
            {
                mdlViews.Add(new TreeMainDto()
                {
                    Id = mdl.Id,
                    MdlCode = mdl.ModuleCode,
                    MdlName = mdl.ModuleName,
                    IconCls = mdl.IconCls,
                    //双问号(??)是一个单元运算符，
                    //其左右两边数据类型必须是相同类型或能隐形转换类型的。
                    //意思是，首先检测左边的值，若为Null，那么整个表达式取值为右侧的值，
                    //否则为左侧的值
                    //如果url的值为空的话 就走右边拼接的code
                    //如果不为空的话就走左边的url
                    ModuleUrl = mdl.ModuleUrl ?? "/" + mdl.ModuleCode,
                    path = mdl.ModuleUrl ?? "/" + mdl.ModuleCode,
                    children = GetChildrenMdl(data, mdl.ModuleCode),
                    Functions = new List<TreeMainDto>()
                });
            }
            return mdlViews;
        }

        private List<TreeMainDto> GetChildrenMdl(List<AppModuleDto> allMdl, string mdlCode)
        {
            //查询传来的AppmodileDto code 是否等于传来的参数mdlcode 并且模型类型为M的
            var childModule = allMdl.FindAll(c => c.ParentModuleCode == mdlCode && c.ModuleType == "M");
            //查询出来子model通过modelseq排序赋值给List显示出来
            var list = childModule.OrderBy(s => s.ModuleSeq).ToList();
            //实例化TreeMainDto表
            var dptView = new List<TreeMainDto>();
            foreach (var mdl in list)
            {
                //因为实例化完这个表是空的 所以要往里添加数据
                dptView.Add(new TreeMainDto()
                {
                    Id = mdl.Id,
                    MdlCode = mdl.ModuleCode,
                    MdlName = mdl.ModuleName,
                    IconCls = mdl.IconCls,
                    ModuleUrl = mdl.ModuleUrl,
                    path = mdl.ModuleUrl,
                    children = GetChildrenMdl(allMdl, mdl.ModuleCode),
                    //调用获取F级的方法
                    Functions = GetFunctionsMdl(allMdl, mdl.ModuleCode)
                }); ;
            }
            return dptView;
        }

        private List<TreeMainDto> GetFunctionsMdl(List<AppModuleDto> allMdl, string mdlCode)
        {
            //查询传来的AppmodileDto code 是否等于传来的参数mdlcode 并且模型类型为M的
            var childModule = allMdl.FindAll(c => c.ParentModuleCode == mdlCode && c.ModuleType == "F").OrderBy(c => c.ModuleSeq);
            //实例化TreeMainDto表
            var dptView = new List<TreeMainDto>();
            foreach (var mdl in childModule)
            {
                dptView.Add(new TreeMainDto()
                {
                    Id = mdl.Id,
                    MdlCode = mdl.ModuleCode,
                    MdlName = mdl.ModuleName,
                    IconCls = mdl.IconCls,
                    ModuleUrl = mdl.ModuleUrl,
                    path = mdl.ModuleUrl
                });
            }
            return dptView;
        }

        /// <summary>
        /// 根据roleId查询所有的菜单信息并标注权限是否拥有***
        /// </summary>
        /// <param name="roleid"></param>
        /// <returns></returns>
        public async Task<List<TreeSysRightDto>> GetSysRoleRights(string roleid, string mdlCode)
        {
            //实例化一个string集合
            List<string> ids = new List<string>();
            //如果传过来的参数mdlCode不为空的话
            if (!string.IsNullOrEmpty(mdlCode))
            {
                //就调用获取Ids的方法赋值给实例化的Ids
                ids = await GetIds(mdlCode);
            }
            //实例化模块表
            List<SysModule> allModuless = await _client.Queryable<SysModule>()
                //条件判断 如果传过来的参数mdlCode不为空,
                //Ids包含模块表中的Id就显示
                .WhereIF(!string.IsNullOrEmpty(mdlCode), it => ids.Contains(it.Id))
                .ToListAsync();
            List<SysRight> roleRightses = await _client.Queryable<SysRight>().Where(it => it.RgtRoleId == roleid).ToListAsync();//问题
            var mdlViews = new List<TreeSysRightDto>();
            var firstModules = allModuless
                .Where(c => c.MdlParent == AppModuleDto.RootModuleCode)
                .OrderBy(c => c.MdlSeq).ToList();
            //然后在循环添加到实例话的TreeSysRightsDto 中
            foreach (var mdl in firstModules)
            {
                mdlViews.Add(new TreeSysRightDto()
                {
                    id = mdl.Id,
                    MdlName = mdl.MdlName,
                    //获取下一级mdl赋值给childern
                    children = GetChildrenMdl(allModuless, mdl.MdlCode, roleRightses),
                    //上面查询出来的数据赋值给roleRightses 
                    //现在根据上面查询出来的roleRightses中模块Id是否等于角色模块表中的模块Id 不可以为空
                    //赋值给HasRights
                    HasRights = roleRightses.Find(c => c.RgtMdlId == mdl.Id) != null,
                    Functions = new List<TreeSysRightDto>()
                });
            }
            return mdlViews;
        }

        /// <summary>
        /// 根据模块代码模块id集合
        /// </summary>
        /// <param name="mdlCode"></param>
        /// <returns></returns>
        public async Task<List<string>> GetIds(string mdlCode)
        {
            //id集合
            List<string> ids = new List<string>();

            //一级-平台
            var dataFirst = await _client.Queryable<SysModule>().
                Select(it => new SysModule { Id = it.Id, MdlCode = it.MdlCode }).
                FirstAsync(it => it.MdlCode == mdlCode);
            if (dataFirst != null)
            {
                ids.Add(dataFirst.Id);
                //二级-导航栏
                var dataSecond = await _client.Queryable<SysModule>().Where(it => it.MdlParent == dataFirst.MdlCode)
                    .Select(it => new SysModule { Id = it.Id, MdlCode = it.MdlCode }).ToListAsync();
                foreach (var sItem in dataSecond)
                {
                    ids.Add(sItem.Id);
                    //三级-导航
                    List<SysModule> dataThird = await _client.Queryable<SysModule>().Where(it => it.MdlParent == sItem.MdlCode)
                        .Select(it => new SysModule { Id = it.Id, MdlCode = it.MdlCode }).ToListAsync();
                    foreach (var tItem in dataThird)
                    {
                        ids.Add(tItem.Id);
                        //四级-按钮
                        var dataFourth = await _client.Queryable<SysModule>().Where(it => it.MdlParent == tItem.MdlCode)
                            .Select(it => it.Id).ToListAsync();
                        foreach (var fItem in dataFourth)
                        {
                            ids.Add(fItem);
                        }
                    }
                }
            }
            return ids;
        }

        private List<TreeSysRightDto> GetChildrenMdl(List<SysModule> allMdl, string mdlCode, List<SysRight> roleRightses)
        {
            //条件查询:模块表中的父快代码等于传过来的参数mdlCode 并且类型等于M 根据模块序号 排列 再赋值给childModule变量
            var childModule = allMdl.FindAll(c => c.MdlParent == mdlCode && c.MdlType == "M").OrderBy(c => c.MdlSeq);
            var dptView = new List<TreeSysRightDto>();
            foreach (var mdl in childModule)
            {
                dptView.Add(new TreeSysRightDto()
                {
                    id = mdl.Id,
                    MdlName = mdl.MdlName,
                    //获取下一级
                    children = GetChildrenMdl(allMdl, mdl.MdlCode, roleRightses),
                    //获取F级
                    Functions = GetFunctionsMdl(allMdl, mdl.MdlCode, roleRightses),
                    //条件查询:角色模块表中的模块Id 等于childModule中的模块Id 不可以为空
                    HasRights = roleRightses.Find(c => c.RgtMdlId == mdl.Id) != null
                }); ;
            }
            return dptView;
        }

        private List<TreeSysRightDto> GetFunctionsMdl(List<SysModule> allMdl, string mdlCode, List<SysRight> roleRightses)
        {
            //获取F级条件查询:模块表中的父快代码等于传过来的参数mdlCode 并且类型等于F 根据模块序号 排列 再赋值给childModule变量
            var childModule = allMdl.FindAll(c => c.MdlParent == mdlCode && c.MdlType == "F").OrderBy(c => c.MdlSeq);
            var dptView = new List<TreeSysRightDto>();
            foreach (var mdl in childModule)
            {
                dptView.Add(new TreeSysRightDto()
                {
                    id = mdl.Id,
                    MdlName = mdl.MdlName,
                    //根据上面传的List合集 roleRightses中模块Id是否等于角色模块表中的模块Id 不可以为空
                    HasRights = roleRightses.Find(c => c.RgtMdlId == mdl.Id) != null
                }); ;
            }
            return dptView;
        }

        /// <summary>
        /// 更新角色权限(可更新特定平台)***
        /// </summary>
        /// <param name="roleid"></param>
        /// <param name="rights"></param>
        /// <returns></returns>
        public async Task<ResponseMessageModel> SysRightUpdate(string roleid, List<string> rights)
        {
            //判断当前登录用户是否管理员
            if (!await IsAdminAsync())
            {
                //如果不是管理员就不允许修改角色权限
                return ToJsonTran.Fail("所在角色禁止修改权限！");
            }
            //如果是管理员就判断这个角色是否存在
            //条件查询:根据角色表中的Id 和传过来的参数Id 是否一致 并且 未删除的角色
            //GetEnumValue:获取枚举值  IsDel是否删除字段
            if (!await _client.Queryable<SysRole>().Where(it => it.Id == roleid && it.Isdel == IsDel.No.GetEnumValue()).AnyAsync())
            {
                //如果为查询到就提示角色不存在
                return ToJsonTran.Fail("角色不存在");
            }

            var data = rights.Select(it => new SysRight() { Id = Ids.NextIdString(), RgtRoleId = roleid, RgtMdlId = it }).ToList();
            if (data.Count > 0)
            {
                await _client.Insertable<SysRight>(data).ExecuteCommandAsync();
            }
            return ToJsonTran.Success();
        }



        /// <summary>
        /// 判断当前登录用户是否管理员
        /// </summary>
        /// <returns></returns>
        public async Task<bool> IsAdminAsync()
        {
            try
            {
                //获取当前登录用户
                var user = AppManager.GetCurrentUser();
                //两表联查: 用户角色表和角色表 进行左连接
                //链接条件用户角色表的角色Id
                //等于角色表的Id 条件 用户角色表的用户Id
                //等于刚才上面获取当前登录用户的Id 并且是否为管理员要为1 (是管理员)
                //查询出来的数据赋值给data
                var data = await _client.Queryable<SysUserrole>()
                    .LeftJoin<SysRole>((su, sy) => su.RleId == sy.Id)
                    .Where((su, sy) => su.UerId == user.UserId && sy.RleIsp == "1")
                    .CountAsync();
                //对刚才 赋值的data进行判断 是否为空
                if (data > 0)
                {
                    //不为空显示为true
                    return true;
                }
                //为空显示false
                return false;
            }
            catch (System.Exception e)
            {
                return false;
            }
        }




    }
}
